#ifndef _TYPES_H_
#define _TYPES_H_

#define MAX_NAME_LEN    128     

/******************************************************************************
* SECTION: Type def
*******************************************************************************/
typedef int          boolean;
typedef uint16_t     flag16;

typedef enum gofs_file_type {
    GOFS_REG_FILE,
    GOFS_DIR,
    GOFS_SYM_LINK
} GOFS_FILE_TYPE;
/******************************************************************************
* SECTION: Macro
*******************************************************************************/
#define TRUE                    1
#define FALSE                   0
#define UINT32_BITS             32
#define UINT8_BITS              8

#define GOFS_MAGIC_NUM           0x52415453  
#define GOFS_SUPER_OFS           0
#define GOFS_ROOT_INO            0



#define GOFS_ERROR_NONE          0
#define GOFS_ERROR_ACCESS        EACCES
#define GOFS_ERROR_SEEK          ESPIPE     
#define GOFS_ERROR_ISDIR         EISDIR
#define GOFS_ERROR_NOSPACE       ENOSPC
#define GOFS_ERROR_EXISTS        EEXIST
#define GOFS_ERROR_NOTFOUND      ENOENT
#define GOFS_ERROR_UNSUPPORTED   ENXIO
#define GOFS_ERROR_IO            EIO     /* Error Input/Output */
#define GOFS_ERROR_INVAL         EINVAL  /* Invalid Args */

#define GOFS_MAX_FILE_NAME       128
#define GOFS_INODE_PER_FILE      1
#define GOFS_DATA_PER_FILE       16
#define GOFS_DEFAULT_PERM        0777

#define GOFS_IOC_MAGIC           'S'
#define GOFS_IOC_SEEK            _IO(GOFS_IOC_MAGIC, 0)

#define GOFS_FLAG_BUF_DIRTY      0x1
#define GOFS_FLAG_BUF_OCCUPY     0x2
/******************************************************************************
* SECTION: Macro Function
*******************************************************************************/
#define GOFS_IO_SZ()                     (gofs_super.sz_io)
#define GOFS_BLK_SZ()                    (gofs_super.sz_block)
#define GOFS_DISK_SZ()                   (gofs_super.sz_disk)
#define GOFS_DRIVER()                    (gofs_super.driver_fd)

#define GOFS_ROUND_DOWN(value, round)    (value % round == 0 ? value : (value / round) * round)
#define GOFS_ROUND_UP(value, round)      (value % round == 0 ? value : (value / round + 1) * round)

#define GOFS_BLKS_SZ(blks)               (blks * GOFS_BLK_SZ())
#define GOFS_ASSIGN_FNAME(pgofs_dentry, _fname)\ 
                                        memcpy(pgofs_dentry->fname, _fname, strlen(_fname))
#define GOFS_INO_OFS(ino)                (gofs_super.inode_offset + ino * GOFS_BLK_SZ())
// 采用data map之后不需要这个
// #define GOFS_DATA_OFS(ino)               (gofs_super.data_offset + GOFS_BLKS_SZ(GOFS_DATA_PER_FILE * ino))

#define GOFS_IS_DIR(pinode)              (pinode->dentry->ftype == GOFS_DIR)
#define GOFS_IS_REG(pinode)              (pinode->dentry->ftype == GOFS_REG_FILE)
#define GOFS_IS_SYM_LINK(pinode)         (pinode->dentry->ftype == GOFS_SYM_LINK)
/******************************************************************************
* SECTION: FS Specific Structure - In memory structure
*******************************************************************************/
struct gofs_dentry;
struct gofs_inode;
struct gofs_super;

struct custom_options {
	const char*        device;
	boolean            show_help;
};

#define GOFS_NDIRECT 15 // 直接索引
#define GOFS_NINDIRECT (GOFS_BLK_SZ() / sizeof(int)) // 间接索引
#define GOFS_MAXFILE (GOFS_NDIRECT + GOFS_NINDIRECT) // 最大数量
struct gofs_inode
{
    int                ino;                           /* 在inode位图中的下标 */
    int                size;                          /* 文件已占用空间 */
    char               target_path[GOFS_MAX_FILE_NAME];/* store traget path when it is a symlink */
    int                dir_cnt;
    struct gofs_dentry* dentry;                        /* 指向该inode的dentry */
    struct gofs_dentry* dentrys;                       /* 所有目录项 */
    uint8_t*           data;           
    int                addr[GOFS_NDIRECT + 1];          /* 磁盘块的物理位置 */
    int*               addr1;                           /* 一级间接索引在内存中的指针 */
};  

struct gofs_dentry
{
    char               fname[GOFS_MAX_FILE_NAME];
    struct gofs_dentry* parent;                        /* 父亲Inode的dentry */
    struct gofs_dentry* brother;                       /* 兄弟 */
    int                ino;
    struct gofs_inode*  inode;                         /* 指向inode */
    GOFS_FILE_TYPE      ftype;
};

struct gofs_super
{
    int                driver_fd;
    
    int                sz_io; // 设备IO大小
    int                sz_block; // 块大小
    int                sz_disk; // 设备磁盘总大小
    int                sz_usage;
    
    int                max_ino; // inode最大数量
    uint8_t*           map_inode; // inode map内存指针
    int                map_inode_blks; // inode map占用块数
    int                map_inode_offset; // inode map在磁盘中的偏移
    
    uint8_t*           map_data;
    int                map_data_blks;
    int                map_data_offset;

    int                inode_offset; // inode数组在磁盘中的偏移
    int                data_offset; // data区域在磁盘中的偏移

    boolean            is_mounted;

    struct gofs_dentry* root_dentry;
};

static inline struct gofs_dentry* new_dentry(char * fname, GOFS_FILE_TYPE ftype) {
    struct gofs_dentry * dentry = (struct gofs_dentry *)malloc(sizeof(struct gofs_dentry));
    memset(dentry, 0, sizeof(struct gofs_dentry));
    GOFS_ASSIGN_FNAME(dentry, fname);
    dentry->ftype   = ftype;
    dentry->ino     = -1;
    dentry->inode   = NULL;
    dentry->parent  = NULL;
    dentry->brother = NULL;                                            
}
/******************************************************************************
* SECTION: FS Specific Structure - Disk structure
*******************************************************************************/
struct gofs_super_d
{
    uint32_t           magic_num;
    int                sz_usage;
    
    int                max_ino; // inode最大数量
    int                map_inode_blks; // inode map所占block数量
    int                map_inode_offset;
    int                map_data_blks; // data map所占block数量
    int                map_data_offset;
    int                inode_offset;
    int                data_offset;
};

struct gofs_inode_d
{
    int                ino;                           /* 在inode位图中的下标 */
    int                size;                          /* 文件已占用空间 */
    char               target_path[GOFS_MAX_FILE_NAME];/* store traget path when it is a symlink */
    int                dir_cnt;
    GOFS_FILE_TYPE      ftype;   
    int                addr[GOFS_NDIRECT + 1];          /* 磁盘块的物理位置 */
};  

struct gofs_dentry_d
{
    char               fname[GOFS_MAX_FILE_NAME];
    GOFS_FILE_TYPE      ftype;
    int                ino;                           /* 指向的ino号 */
};  


#endif /* _TYPES_H_ */